Skip to content

fix(templates): resolve GitHub API host from env in ralph-triage.js#1438

Open
omercangumus wants to merge 1 commit into
bradygaster:devfrom
omercangumus:omercangumus/1142-ralph-triage-ghe-api-host
Open

fix(templates): resolve GitHub API host from env in ralph-triage.js#1438
omercangumus wants to merge 1 commit into
bradygaster:devfrom
omercangumus:omercangumus/1142-ralph-triage-ghe-api-host

Conversation

@omercangumus

@omercangumus omercangumus commented Jul 2, 2026

Copy link
Copy Markdown

What

ralph-triage.js now resolves the GitHub REST API host from the environment instead of hardcoding api.github.com.

Why

Squad Heartbeat (Ralph) fails with a 401 on GitHub Enterprise. githubRequestJson() in .squad-templates/ralph-triage.js sent every request to hostname: 'api.github.com', but on GHE the GITHUB_TOKEN is only valid against the enterprise API host (https://<ghe-host>/api/v3), so calls to github.com are rejected with Bad credentials.

Closes #1142

How

Added a resolveGithubApiBase() helper that picks the API base in order:

  1. GITHUB_API_URL — set automatically by Actions on both github.com and GHE runners.
  2. GITHUB_SERVER_URL + /api/v3 — fallback for GHE if GITHUB_API_URL isn't set.
  3. https://api.github.com — fallback for local/non-Actions runs.

githubRequestJson() now builds the request from a URL object (${resolveGithubApiBase()}${pathname}) instead of a hardcoded hostname/path pair, so https.request() picks up the correct protocol, host, and base path automatically. No behavior change on github.com-hosted repos, since GITHUB_API_URL there already resolves to https://api.github.com.

Fixed in the canonical .squad-templates/ralph-triage.js and propagated via node scripts/sync-templates.mjs --sync to the 3 mirror targets (templates/, packages/squad-cli/templates/, packages/squad-sdk/templates/), matching the parity checks in test/template-sync.test.ts.

Also added a require.main === module guard around the script's main() call and exported resolveGithubApiBase via module.exports, purely so the new unit tests can import and exercise the helper without invoking main() (which needs GITHUB_TOKEN and network access). No change to the script's behavior when run directly via node ralph-triage.js.

Testing

  • Added 4 new unit tests in test/ralph-triage.test.ts covering all three resolution branches plus trailing-slash normalization. Verified they fail with resolveGithubApiBase is not a function against the pre-fix code and pass against the fix.
  • npx vitest run test/ralph-triage.test.ts test/template-sync.test.ts — 284 passed.
  • npm run build — passes.
  • npm run lint (tsc --noEmit) — passes.
  • npm run lint:eslint — 0 errors (pre-existing warnings only, unrelated to this change).
  • npm test (full suite) — no regressions from this change. A number of unrelated tests fail on this Windows dev machine (EBUSY temp-dir races, timing-sensitive timeouts, a locale-dependent number-formatting assertion) — confirmed identical failures on a clean upstream/dev checkout before my changes, so they're pre-existing local-environment flakiness, not something this PR introduces.

⚠️ Quick Check

  • Changeset added via npx changeset add-equivalent manual file: .changeset/fix-1142-ralph-triage-ghe-api-host.md (patch bump for @bradygaster/squad-cli and @bradygaster/squad-sdk, since this touches governed template paths under both packages' templates/)

PR Readiness Checklist

Branch & Commit

  • Branch created from dev
  • Branch is up to date with dev
  • Verified diff contains only intended changes (git diff --cached --stat)
  • PR is not in draft mode — will mark ready once CI is green
  • Commit history is clean (single commit)

Build & Test

  • npm run build passes
  • npm test passes (all tests relevant to this change; see testing notes above for pre-existing unrelated local failures)
  • npm run lint passes (type check clean)
  • npm run lint:eslint passes (0 errors)

Changeset

  • Changeset added (patch, both packages)

Docs

  • N/A — internal script fix, no user-facing CLI/SDK API change

Exports

  • N/A — no new modules

Breaking Changes

None.

Waivers

None.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🟠 Impact Analysis — PR #1438

Risk tier: 🟠 HIGH

📊 Summary

Metric Count
Files changed 7
Files added 1
Files modified 6
Files deleted 0
Modules touched 6

🎯 Risk Factors

  • 7 files changed (6-20 → MEDIUM)
  • 6 modules touched (5-8 → HIGH)

📦 Modules Affected

docs (1 file)
  • docs/src/content/docs/scenarios/ci-cd-integration.md
root (2 files)
  • .changeset/fix-1142-ralph-triage-ghe-api-host.md
  • templates/ralph-triage.js
squad-cli (1 file)
  • packages/squad-cli/templates/ralph-triage.js
squad-sdk (1 file)
  • packages/squad-sdk/templates/ralph-triage.js
templates (1 file)
  • .squad-templates/ralph-triage.js
tests (1 file)
  • test/ralph-triage.test.ts

This report is generated automatically for every PR. See #733 for details.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 58ca57b

PR Scope: 🔧 Infrastructure

⚠️ 2 item(s) to address before review

Status Check Details
Single commit 1 commit — clean history
Not in draft Ready for review
Branch up to date Up to date with dev
Copilot review No Copilot review yet — it may still be processing
Changeset present Changeset file found
Scope clean No .squad/ or docs/proposals/ files
No merge conflicts No merge conflicts
Copilot threads resolved No Copilot review threads
CI passing 5 check(s) still running

Files Changed (7 files, +164 −25)

File +/−
.changeset/fix-1142-ralph-triage-ghe-api-host.md +10 −0
.squad-templates/ralph-triage.js +28 −6
docs/src/content/docs/scenarios/ci-cd-integration.md +2 −0
packages/squad-cli/templates/ralph-triage.js +28 −6
packages/squad-sdk/templates/ralph-triage.js +28 −6
templates/ralph-triage.js +28 −6
test/ralph-triage.test.ts +40 −1

Total: +164 −25


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

@omercangumus omercangumus marked this pull request as ready for review July 3, 2026 05:49
@tamirdresher

Copy link
Copy Markdown
Collaborator

Thanks @omercangumus for this. It was indeed needed. Can you pleae also update the docs so users could be able to discover about this option?

ralph-triage.js hardcoded hostname: 'api.github.com' in its
https.request() call, so Squad Heartbeat (Ralph) failed with a 401 on
GitHub Enterprise — the GITHUB_TOKEN there is only valid against the
enterprise API host, not github.com.

Added resolveGithubApiBase(), which picks the API base in order:
GITHUB_API_URL (set by Actions on both github.com and GHE runners),
then GITHUB_SERVER_URL + /api/v3, then https://api.github.com as a
last-resort fallback. The request is now built from a URL object
instead of a hardcoded hostname/path pair. No behavior change on
github.com-hosted repos.

Fixed in the canonical .squad-templates/ralph-triage.js and synced to
the 3 mirror targets. Added unit tests covering all three resolution
branches.

Documented the env var resolution order in the CI/CD integration docs
so GHE users can discover it.

Closes bradygaster#1142

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@omercangumus omercangumus force-pushed the omercangumus/1142-ralph-triage-ghe-api-host branch from ae02c82 to 58ca57b Compare July 3, 2026 11:26
@omercangumus

Copy link
Copy Markdown
Author

good call, added a note in docs/src/content/docs/scenarios/ci-cd-integration.md right next to the cron callout, explains the GITHUB_API_URL/GITHUB_SERVER_URL fallback order and how to set it manually if running heartbeat outside Actions. lmk if you'd rather it live somewhere else

@tamirdresher tamirdresher left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved — security review passed.

Security checks:

  • No SSRF risk: env vars (GITHUB_API_URL, GITHUB_SERVER_URL) are Actions-runner-controlled, not user-input-derived
  • URL validation via
    ew URL()\ prevents malformed URL injection
  • Trailing-slash stripping prevents path confusion
  • Minimal export surface (only resolveGithubApiBase)
  • No prompt injection vectors — pure HTTP infra

Correctness: Resolution order (GITHUB_API_URL → SERVER_URL+/api/v3 → fallback) matches GitHub's own documented env vars. Tests cover all 4 branches including trailing-slash normalization.
equire.main === module\ guard + exports for testability is textbook.

Good contribution, Ömer 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ralph-triage.js hardcodes api.github.com, causing 401 on GitHub Enterprise

2 participants